﻿/*
 *  ChgDoc CMS - GNU General Public License, version 3 (GPL-3.0)
 *  Copyright (C)  2012. Ian Quigley
 *  
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using SqliteORM;

namespace ChgDoc.Edit
{
	public abstract class BasePage : System.Web.UI.Page
	{
        private IEnumerable<FormRule> _staticFormRules;
		private IEnumerable<FormRule> StaticFormRules
		{
            get
            {
                if (_staticFormRules == null)
                    _staticFormRules = GetFormRules();

                return (IEnumerable<FormRule>)_staticFormRules;
            }
		}

		protected virtual IEnumerable<FormRule> GetFormRules()
		{
			return null;
		}

        protected virtual IEnumerable<FormError> ValidateRulesAndMap<T>(T t)
        {
        	if (StaticFormRules == null)
				yield break;

			foreach (var validate in StaticFormRules)
			{
                object val = ValueFromControl( validate );

				if (validate.HasCondition(FormRuleCondition.NotNull))
				{
					if ( string.IsNullOrWhiteSpace( val as string))
						yield return new FormError( validate.DisplayName + " cannot be empty" );
				}

				if (validate.HasCondition(FormRuleCondition.AZaz09))
				{
					Regex match = new Regex( "[a-zA-Z0-9]" );
					if (match.IsMatch( val as string))
						yield return new FormError( validate.DisplayName + " can only consist of characters a-z A-Z 0-9" );
				}

                FormError fe = null;
                try
                {
                    if (validate is FormRuleMapping<T>)
                        ((FormRuleMapping<T>)validate).Set(t, val);
                }
                catch (Exception ex)
                {
                    fe = new FormError(validate.DisplayName + " threw exception: " + ex.Message);
                }
                if (fe != null)
                    yield return fe;
			}

			yield break;
		}

        private static object ValueFromControl( FormRule validate )
        {
            object val = null;
            if (validate.Control is TextBox)
                val = ((TextBox)validate.Control).Text;

            if (validate.Control is DropDownList)
                val = ((DropDownList)validate.Control).SelectedValue;

            if (validate.Control is CheckBox)
                val = ((CheckBox)validate.Control).Checked;

            return val;
        }

		protected void SetTitle(string title)
		{
			((Admin) Master).SetTitle( title );
		}

		protected virtual bool PopulateModelFromControls<T>(T thing)
		{
            ((Admin)Master).ClearMessage();

			var errors = ValidateRulesAndMap<T>(thing);
			if (!errors.Any())
				return true;

			var forAdmin = from err in errors select err.ToAdmin();
			((Admin)Master).SetMessage( forAdmin );

			return false;
		}

        protected bool HasParam(string name)
        {
            return !string.IsNullOrEmpty(Request.QueryString[name]);
        }

        protected long LongParam(string name, long @default = 0)
		{
			if (Request.QueryString[name] == null)
				return @default;

			long l;
			if (long.TryParse( Request.QueryString[name], out l ) == false)
				return @default;

			return l;
		}

        protected void DoReturnUrl()
        {
            if (Request.QueryString[ "ReturnUrl" ] != null)
                Response.Redirect( Request.QueryString[ "ReturnUrl" ] );
        }

		protected string Param(string name)
		{
			return Request.QueryString[ name ];
		}

	}

	public class FormError
	{
		public string Message { get; set; }

		public FormError(string message)
		{
			Message = message;
		}

		public Tuple<Admin.MessageLevel,string> ToAdmin()
		{
			return new Tuple<Admin.MessageLevel, string>( Admin.MessageLevel.Error, Message );
		}
	}

    public class FormRuleMapping<T> : FormRule
    {
        public Action<T, object> Set { get; private set; }
        
        public FormRuleMapping(Control control, string displayName, FormRuleCondition condition, Action<T, object> set) 
        : base(control, displayName, condition)
        {
            Set = set;
        }
    }

	public class FormRule
	{
		public string DisplayName { get; set; }
		public Control Control { get; set; }
		public FormRuleCondition Condition { private get; set; }
		
		public bool HasCondition (FormRuleCondition value)
		{
			return ((Condition & value) == value);
		}


		public FormRule(Control control, string displayName, FormRuleCondition condition)
		{
			DisplayName = displayName;
			Control = control;
			Condition = condition;
		}
	}

	[Flags]
	public enum FormRuleCondition
	{
			None = 0x0000, 
			NotNull = 0x0001, 
			AZaz09 = 0x0010
	}
}